//
//  ReactorKitTest2ViewController.swift
//  iOS-RxSwift-Tutorials_Example
//
//  Created by mengru.tian on 2020/9/24.
//  Copyright © 2020 CocoaPods. All rights reserved.
//

import UIKit
import RxSwift
import ReactorKit
import RxCocoa


    final class ViewReactor2: Reactor {
         
        //GitHub网络请求服务
        let networkService = GitHubNetworkService3()
         
        //用户注册服务
        let signupService = GitHubSignupService()
         
        //代表用户行为
        enum Action {
            case usernameChanged(String) //用户名输入
            case passwordChanged(String) //密码输入
            case repeatedPasswordChanged(String) //重复密码输入
            case signup //用户注册
        }
         
        //代表状态变化
        enum Mutation {
            case setUsername(String) //设置用户名
            case setUsernameValidationResult(ValidationResult) //设置用户名验证结果
            case setPassword(String) //设置密码
            case setPasswordValidationResult(ValidationResult) //设置用户名验证结果
            case setRepeatedPassword(String) //设置重复密码
            case setRepeatedPasswordValidationResult(ValidationResult) //设置重复密码验证结果
            case setStartSignup(Bool) //设置注册状态（是否正在提交注册）
            case setSignupResult(Bool?) //设置注册结果
        }
         
        //代表页面状态
        struct State {
            var username: String //用户名
            var password: String //密码
            var repeatedPassword: String //再出输入密码
            var usernameValidationResult: ValidationResult //用户名验证结果
            var passwordValidationResult: ValidationResult //密码验证结果
            var repeatedPasswordValidationResult: ValidationResult //重复密码验证结果
            var startSignup: Bool //开始注册
            var signupResult: Bool? //注册结果
        }
         
        //初始页面状态
        let initialState: State
         
        init() {
            self.initialState = State(
                username: "",
                password: "",
                repeatedPassword: "",
                usernameValidationResult: ValidationResult.empty,
                passwordValidationResult: ValidationResult.empty,
                repeatedPasswordValidationResult: ValidationResult.empty,
                startSignup: false,
                signupResult: nil
            )
        }
         
        //实现 Action -> Mutation 的转换
        func mutate(action: Action) -> Observable<Mutation> {
            switch action {
            //用户名变化
            case let .usernameChanged(username):
                //依次执行下面2个状态变化动作
                return Observable.concat([
                    //设置用户名
                    Observable.just(Mutation.setUsername(username)),
                    //设置用户名验证结果
                    signupService.validateUsername(username)
                        //如果用户名再次变化，但上一次验证还未完成，上一次验证会自动取消
                        .takeUntil(self.action.filter(isUsernameChangedAction))
                        .map(Mutation.setUsernameValidationResult)
                    ])
            //密码变化
            case let .passwordChanged(password):
                //依次执行下面2个状态变化动作
                return Observable.concat([
                    //设置密码
                    Observable.just(Mutation.setPassword(password)),
                    //设置密码验证结果
                    Observable.just( Mutation.setPasswordValidationResult(
                        signupService.validatePassword(password))
                    ),
                    //设置重复密码验证结果
                    Observable.just( Mutation.setRepeatedPasswordValidationResult(
                        signupService.validateRepeatedPassword(
                            password,
                            repeatedPassword: self.currentState.repeatedPassword )
                        )
                    )
                    ])
            //重复密码变化
            case let .repeatedPasswordChanged(repeatedPassword):
                //依次执行下面2个状态变化动作
                return Observable.concat([
                    //设置重复密码
                    Observable.just(Mutation.setRepeatedPassword(repeatedPassword)),
                    //设置重复密码验证结果
                    Observable.just( Mutation.setRepeatedPasswordValidationResult(
                        signupService.validateRepeatedPassword(
                            self.currentState.password,
                            repeatedPassword: repeatedPassword )
                        )
                    )
                    ])
            //注册按钮点击
            case .signup:
                //依次执行下面4个状态变化动作
                return Observable.concat([
                    //先清空之前的结果
                    Observable.just(Mutation.setSignupResult(nil)),
                    //开始注册
                    Observable.just(Mutation.setStartSignup(true)),
                    //设置注册结果
                    networkService.signup(self.currentState.username,
                                          password: self.currentState.password)
                        .map(Mutation.setSignupResult),
                    //注册结束
                    Observable.just(Mutation.setStartSignup(false))
                    ])
            }
        }
         
        //实现 Mutation -> State 的转换
        func reduce(state: State, mutation: Mutation) -> State {
            //从旧状态那里复制一个新状态
            var state = state
             
            //根据状态变化设置响应的状态值
            switch mutation {
            //设置用户名
            case let .setUsername(username):
                state.username = username
                state.signupResult = nil //信息一有变化则清除注册结果
            //设置用户名验证结果
            case let .setUsernameValidationResult(validationResult):
                state.usernameValidationResult = validationResult
            //设置密码
            case let .setPassword(password):
                state.password = password
                state.signupResult = nil //信息一有变化则清除注册结果
            //设置密码验证结果
            case let .setPasswordValidationResult(validationResult):
                state.passwordValidationResult = validationResult
            //设置重复密码
            case let .setRepeatedPassword(repeatedPassword):
                state.repeatedPassword = repeatedPassword
                state.signupResult = nil //信息一有变化则清除注册结果
            //设置重复密码验证结果
            case let .setRepeatedPasswordValidationResult(validationResult):
                state.repeatedPasswordValidationResult = validationResult
            //设置注册状态
            case let .setStartSignup(value):
                state.startSignup = value
            //设置注册结果
            case let .setSignupResult(value):
                state.signupResult = value
            }
             
            //返回新状态
            return state
        }
         
        //判断当前的 action 是否是用户名输入
        private func isUsernameChangedAction(_ action: Action) -> Bool {
            if case .usernameChanged = action {
                return true
            } else {
                return false
            }
        }
    }


class ReactorKitTest2ViewController: UIViewController,StoryboardView {
    
    var disposeBag = DisposeBag()
    
    typealias Reactor = ViewReactor2
    
    
    //用户名输入框、以及验证结果显示标签
    @IBOutlet weak var usernameOutlet: UITextField!
    @IBOutlet weak var usernameValidationOutlet: UILabel!
     
    //密码输入框、以及验证结果显示标签
    @IBOutlet weak var passwordOutlet: UITextField!
    @IBOutlet weak var passwordValidationOutlet: UILabel!
     
    //重复密码输入框、以及验证结果显示标签
    @IBOutlet weak var repeatedPasswordOutlet: UITextField!
    @IBOutlet weak var repeatedPasswordValidationOutlet: UILabel!
     
    //注册按钮
    @IBOutlet weak var signupOutlet: UIButton!
     
    //注册时的活动指示器
    @IBOutlet weak var signInActivityIndicator: UIActivityIndicatorView!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        title = "66.ReactorKit架构2：一个用户注册样例"
        view.backgroundColor = .white
        
        //设置reactor，会自动触发bind()方法
        self.reactor = ViewReactor2()
    }
    
    //处理绑定事件（该方法会在 self.reactor 变化时自动触发）
    func bind(reactor: ViewReactor2) {
         
        //Action（实现 View -> Reactor 的绑定）
        usernameOutlet.rx.text.orEmpty.changed  //用户名输入框文字改变事件
            .throttle(0.3, scheduler: MainScheduler.instance)
            .distinctUntilChanged()
            .map(Reactor.Action.usernameChanged)  //转换为 Action.usernameChanged
            .bind(to: reactor.action)  //绑定到 reactor.action
            .disposed(by: disposeBag)
         
        passwordOutlet.rx.text.orEmpty.changed  //密码输入框文字改变事件
            .distinctUntilChanged()
            .map(Reactor.Action.passwordChanged)  //转换为 passwordChanged
            .bind(to: reactor.action)  //绑定到 reactor.action
            .disposed(by: disposeBag)
         
        repeatedPasswordOutlet.rx.text.orEmpty.changed  //重复密码输入框文字改变事件
            .distinctUntilChanged()
            .map(Reactor.Action.repeatedPasswordChanged)  //转换为 repeatedPasswordChanged
            .bind(to: reactor.action)  //绑定到 reactor.action
            .disposed(by: disposeBag)
         
        signupOutlet.rx.tap //注册按钮点击事件
            .map{ Reactor.Action.signup }  //转换为 signup
            .bind(to: reactor.action)  //绑定到 reactor.action
            .disposed(by: disposeBag)
         
        // State（实现 Reactor -> View 的绑定）
        reactor.state.map { $0.usernameValidationResult }  //得到最新用户名验证结果
            .bind(to: usernameValidationOutlet.rx.validationResult)  //绑定到文本标签上
            .disposed(by: disposeBag)
         
        reactor.state.map { $0.passwordValidationResult }  //得到最新密码验证结果
            .bind(to: passwordValidationOutlet.rx.validationResult)  //绑定到文本标签上
            .disposed(by: disposeBag)
         
        reactor.state.map { $0.repeatedPasswordValidationResult }  //得到最新重复密码验证结果
            .bind(to: repeatedPasswordValidationOutlet.rx.validationResult)//绑定到文本标签上
            .disposed(by: disposeBag)
         
        //注册按钮是否可用
        reactor.state.map{ $0.usernameValidationResult.isValid &&
            $0.passwordValidationResult.isValid &&
            $0.repeatedPasswordValidationResult.isValid }
            .observeOn(MainScheduler.instance)
            .subscribe(onNext: { [weak self] valid in
                self?.signupOutlet.isEnabled = valid
                self?.signupOutlet.alpha = valid ? 1.0 : 0.3
            })
            .disposed(by: disposeBag)
         
        //活动指示器绑定
        reactor.state.map { $0.startSignup }
            .bind(to: signInActivityIndicator.rx.isAnimating)
            .disposed(by: disposeBag)
         
        //注册结果显示
        reactor.state.map { $0.signupResult }
            .filter{ $0 != nil }
            .subscribe(onNext: { [weak self] result in
                self?.showMessage("注册" + (result! ? "成功" : "失败") + "!")
            })
            .disposed(by: disposeBag)
    }
     
    //详细提示框
    func showMessage(_ message: String) {
        let alertController = UIAlertController(title: nil,
                                                message: message, preferredStyle: .alert)
        let okAction = UIAlertAction(title: "确定", style: .cancel, handler: nil)
        alertController.addAction(okAction)
        self.present(alertController, animated: true, completion: nil)
    }
}
